import FLOWABLE from './FLOWABLE'

class EditorManager {
  constructor(config) {
    this.config = Object.assign({}, config)
    this.canvasTracker = new Hash();
    this.current = this.modelId;
    this.treeFilteredElements = ["SubProcess", "CollapsedSubProcess"];
    this.structualIcons = {
      "SubProcess": "expanded.subprocess.png",
      "CollapsedSubProcess": "subprocess.png",
      "EventSubProcess": "event.subprocess.png"
    };
    this.loading = true;
  }
  getCurrentModelId() {
    return this.current;
  }
  bootEditor() {
    this.canvasTracker = new Hash();
    var config = Object.assign(this.modelData, {});
    if (!config.model.childShapes) {
      config.model.childShapes = [];
    }
    this.findAndRegisterCanvas(this.config.model.childShapes);
    this.canvasTracker.set(
      this.config.modelId,
      JSON.stringify(this.config.model.childShapes)
    );
    this.editor = new ORYX.Editor(this.config);
    // 没有这个current保存不了变更的数据
    this.current = this.editor.id;
    this.loading = false;
    FLOWABLE.eventBus.editor = this.editor;
    FLOWABLE.eventBus.dispatch("ORYX-EDITOR-LOADED", {});
    FLOWABLE.eventBus.dispatch(FLOWABLE.eventBus.EVENT_TYPE_EDITOR_BOOTED, {});
  }
  findAndRegisterCanvas(childShapes) {
    for (var i = 0; i < childShapes.length; i++) {
      var childShape = childShapes[i];
      if (childShape.stencil.id === "CollapsedSubProcess") {
        if (childShape.childShapes.length > 0) {
          //the canvastracker will auto correct itself with a new canvasmodel see this.edit()...
          this.findAndRegisterCanvas(childShape.childShapes);
          //a canvas can't be nested as a child because the editor would crash on redundant information.
          this.canvasTracker.set(
            childShape.resourceId,
            JSON.stringify(childShape.childShapes)
          );
          //reference to config will clear the value.
          childShape.childShapes = [];
        } else {
          this.canvasTracker.set(
            childShape.resourceId,
            '[]'
          );
        }
      }
    }
  }
  getEditor() {
    return this.editor
  }
  getModelId() {
    return this.modelId;
  }
  getModel() {
    this.syncCanvasTracker();

    var modelMetaData = this.getBaseModelData();
    var stencilId = undefined;
    var stencilSetNamespace = undefined;
    var stencilSetUrl = undefined;
    if (modelMetaData.model.stencilset.namespace == 'http://b3mn.org/stencilset/cmmn1.1#') {
      stencilId = 'CMMNDiagram';
      stencilSetNamespace = 'http://b3mn.org/stencilset/cmmn1.1#';
      stencilSetUrl = '../editor/stencilsets/cmmn1.1/cmmn1.1.json';
    } else {
      stencilId = 'BPMNDiagram';
      stencilSetNamespace = 'http://b3mn.org/stencilset/bpmn2.0#';
      stencilSetUrl = '../editor/stencilsets/bpmn2.0/bpmn2.0.json';
    }
    //this is an object.
    var editorConfig = this.editor.getJSON();
    var model = {
      modelId: this.modelId,
      bounds: editorConfig.bounds,
      properties: editorConfig.properties,
      childShapes: JSON.parse(this.canvasTracker.get(this.modelId)),
      stencil: {
        id: stencilId,
      },
      stencilset: {
        namespace: stencilSetNamespace,
        url: stencilSetUrl
      }
    };
    this._mergeCanvasToChild(model);
    return model;
  }

  getChildShapeByResourceId(resourceId) {
    return this.editor.getCanvas().getChildShapeByResourceId(resourceId);
  }
  isLoading(){
      return this.loading;
  }
  getTree() {
    var result = new Hash();
    var parent = this.getModel();
    console.log(parent, 111)
    result.set("name", parent.properties["name"] || "No name provided");
    result.set("id", this.modelId);
    result.set("type", "root");
    result.set("current", this.current === this.modelId)
    var childShapes = parent.childShapes;
    var children = this._buildTreeChildren(childShapes);
    result.set("children", children);
    return result.toObject();
  }
  _buildTreeChildren(childShapes) {
    var children = [];
    for (var i = 0; i < childShapes.length; i++) {
      var childShape = childShapes[i];
      var stencilId = childShape.stencil.id;
      //we are currently only interested in the expanded subprocess and collapsed processes
      if (stencilId && this.treeFilteredElements.indexOf(stencilId) > -1) {
        var child = new Hash();
        child.set("name", childShape.properties.name || "No name provided");
        child.set("id", childShape.resourceId);
        child.set("type", stencilId);
        child.set("current", childShape.resourceId === this.current);

        //check if childshapes

        if (stencilId === "CollapsedSubProcess") {
          //the save function stores the real object as a childshape
          //it is possible that there is no child element because the user did not open the collapsed subprocess.
          if (childShape.childShapes.length === 0) {
            child.set("children", []);
          } else {
            child.set("children", this._buildTreeChildren(childShape.childShapes));
          }
          child.set("editable", true);
        } else {
          child.set("children", this._buildTreeChildren(childShape.childShapes));
          child.set("editable", false);
        }
        child.set("icon", this.structualIcons[stencilId]);
        children.push(child.toObject());
      }
    }
    return children;
  }
  _mergeCanvasToChild(parent) {
    for (var i = 0; i < parent.childShapes.length; i++) {
      var childShape = parent.childShapes[i]
      if (childShape.stencil.id === "CollapsedSubProcess") {

        var elements = this.canvasTracker.get(childShape.resourceId);
        if (elements) {
          elements = JSON.parse(elements);
        } else {
          elements = [];
        }
        childShape.childShapes = elements;
        this._mergeCanvasToChild(childShape);
      } else if (childShape.stencil.id === "SubProcess") {
        this._mergeCanvasToChild(childShape);
      } else {
        //do nothing?
      }
    }
  }
  setModelId(modelId) {
    this.modelId = modelId;
  }
  setModelDataField(key, value) {
    this.modelData[key] = value
  }
  setModelData(data) {
    this.modelData = data;
  }
  handleEvents(events) {
    this.editor.handleEvents(events);
  }
  getSelection() {
    return this.editor.selection;
  }
  setSelection(selection) {
    this.editor.setSelection(selection);
  }
  registerOnEvent(e, callback) {
    this.editor.registerOnEvent(e, callback);
  }
  unregisterOnEvent(e, callback) {
    this.editor.unregisterOnEvent(e, callback);
  }
  executeCommands(commands) {
    this.editor.executeCommands(commands);
  }
  getCanvas() {
    return this.editor.getCanvas();
  }
  updateSelection() {
    this.editor.updateSelection()
  }
  getBaseModelData() {
    return this.modelData;
  }
  getStencilData() {
    return this.stencilData;
  }
  setStencilData(stencilData) {
    this.stencilData = jQuery.extend(true, {}, stencilData);
  }
  getStencilSets() {
    return this.editor.getStencilSets();
  }
  syncCanvasTracker() {
    var shapes = this.getCanvas().getChildren();
    var jsonShapes = [];
    shapes.each(function (shape) {
      //toJson is an summary object but its not a json string.!!!!!
      jsonShapes.push(shape.toJSON());
    });
    this.canvasTracker.set(this.current, JSON.stringify(jsonShapes));
  }
  getSelection() {
    return this.editor.selection;
  }
  getSubSelection() {
    return this.editor._subSelection;
  }
  getRules() {
    return this.editor.getRules();
  }
  edit(resourceId) {
    this.syncCanvasTracker();
    this.loading = true;
    var shapes = this.getCanvas().getChildren();
    shapes.each(function (shape) {
      this.editor.deleteShape(shape);
    }.bind(this));
    shapes = this.canvasTracker.get(resourceId);
    if (!shapes) {
      shapes = JSON.stringify([]);
    }
    this.editor.loadSerialized({
      childShapes: shapes
    });
    this.getCanvas().update();
    this.current = resourceId;
    this.loading = false;
    FLOWABLE.eventBus.dispatch("EDITORMANAGER-EDIT-ACTION", {});
    FLOWABLE.eventBus.dispatch(FLOWABLE.eventBus.EVENT_TYPE_UNDO_REDO_RESET, {});
  }
  eventCoordinatesXY(x, y) {
    return this.editor.eventCoordinatesXY(x, y);
  }
  eventCoordinates(coordinates) {
    return this.editor.eventCoordinates(coordinates);
  }
}

export default EditorManager